home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************************
- * Engine.c
- *
- * Written by: Rob Langhorne, J. Christopher Bell, and David Fedor
- *
- * Copyright: © 1995-1996 by Apple Computer, Inc. All rights reserved.
- *
- * This file is used both by the Macintosh and Windows versions of SoupDrink; it contains
- * nearly all the calls to the CDIL and FDIL code other than the initialization routines.
- *
- * SoupDrink() is the routine for soup drinking: uploading a soup to the desktop.
- * UploadNewName() sends a frame holding a "name card" to the Newton.
- * PrintEntry() and PrintTree() pretty-print the contents of a frame to a file.
- *
- * Purpose:
- * To demonstrate the basic parts of FDILs and CDILs. The basic engines currently in
- * this code are the "soup drink" engine which uploads a Newton soup and the the
- * "new name" engine which downloads a business card to the Newton names database.
- * This sample can work over any transport, but the SoupDrink sample on the Newton
- * may use "spit" mode over ADSP (because of problems in OutputFrame() that used to
- * exist on Newton 1.x devices prior to the December 1995 patch).
- *
- * The soup drinking is split into two sections to illustrate both synchronous and
- * asynchronous reading. The first entry read is done asynchronously from this
- * function, with the callback function SoupDrinkCallback (below) doing the rest of
- * the communication synchronously.
- *
- * The protocol for the soup drink is:
- * Newton Desktop
- * ====== =======
- * <---- "DRNK"
- * "DRNK" or "SPIT" (depending whether sending frames is supported)-->
- * "ENTR"-->
- * a frame (or a string if in spit mode)--->
- * <---- "OK"
- * [then repeat with ENTR command, or ...]
- * "END "-->
- *
- */
-
- #ifndef _windows
- #define forMac // Codewarrior doesn't have a handy way to do this.
- #endif
-
-
- #include <string.h>
- #include <stdio.h>
-
-
- #ifdef forMac // ****** stuff for MAC-OS applications ******
- #include <Types.h>
- #include <memory.h>
-
- // In the beta 8 CW6 libraries, "MPW C Calling Conventions" needed to be turned on.
- // This does NOT need to be done any more, but I'm leaving in the comment so that
- // people realize the current situation. This comment will self-destruct in 5 seconds.
- // #pragma mpwc on
- #include "DILCPIPE.h"
- #include "HLFDIL.h"
- // #pragma mpwc reset
-
- #include "SoupDrink.h"
- #define Timeout 600 // this is currently in ticks but should be in milliseconds
-
-
- #else // ****** stuff for Windows applications *********
-
- #include <windows.h>
- #include "DILCPIPE.H"
- #include "HLFDIL.h"
- #include "SOUPDRNK.H"
- #define Timeout 20000 // time out in 20 seconds
- typedef unsigned char Str255[256];
-
- #define CurrentTimeInSeconds() ((long)(GetTickCount() / 1000))
-
- #endif
-
-
-
- #include "Engine.h"
- #define kTimeoutInSecs 15
- #define Encoding 0
- #define Swapping 0
-
- extern CDILPipe *ourPipe;
- extern void *gThisObject; // This is the only DIL frame active at one time in this app
- extern int gInputMode; // drink mode (receive frames) or spit mode (receive strings)
- extern char gReceivedString[]; // received string; used in 'spit mode'
- extern long gReceivedStringLen; // received string length (see above)
- extern char gTempBuffer [256]; // a global string buffer for input dialogs, etc
-
- CommErr SoupDrink()
- {
- char soupName[255];
- char response[5];
- long length;
- objErr fErr = 0;
- long longLen;
- Boolean eom;
- long endTime;
-
- inputDialog((char *)soupName, "Names", "Enter Soup Name:");
- if ('\0' == *soupName) /* Probably a cancel */
- return 0;
-
- if (strlen(soupName) > 253)
- soupName[253] = 0;
- strcat((char *)soupName, "\4");
-
- fErr = (short) InitializePipe();
- if (fErr)
- return fErr; // don't need to dispose pipe if error
-
- // make the connection!
- CHECKDILERROR((short) CDPipeListen(ourPipe, kDefaultTimeout, 0, 0));
- #ifndef _windows
- CHECKDILERROR((short) CDPipeAccept(ourPipe));
- #else
- // This code doesn't need to be done on the MacOS side, but is currently required
- // for Windows. You need to loop a little bit for the connection state to be
- // set to kCDIL_ConnectPending. It might not do that if there's nobody on the
- // other side of the cable, though!
-
- // Loop until the Newton device connects
- endTime = CurrentTimeInSeconds() + kTimeoutInSecs; // time at which we should stop looping
- while (CurrentTimeInSeconds() < endTime) {
- if (CDGetPipeState(ourPipe) == kCDIL_ConnectPending) {
- CHECKDILERROR((short) CDPipeAccept(ourPipe));
- break;
- } else
- CDIdle(ourPipe);
- }
-
- if (CurrentTimeInSeconds() >= endTime) { // did we time out?
- CDPipeDisconnect(ourPipe) ;
- return kOurTimeoutError;
- }
- #endif
-
- /* Initiate conversation; tell the Newton that we want to do a 'DRNK' */
- length = 4;
- CHECKDILERROR((short) CDPipeWrite(ourPipe, (void *)"DRNK", &length, true,Swapping,Encoding,Timeout,0,0));
-
- /* send the name of the soup we want to search */
- length = strlen(soupName);
- CHECKDILERROR((short) CDPipeWrite(ourPipe, (void *)soupName, &length, true,Swapping,Encoding,Timeout,0,0));
-
- /* get the Newton response. Possibilities are:
- * "DRNK" -- no problem; about to begin
- * "SPIT" -- DRNK not supported. ADSP and outputframe is a problem on some systems -
- * that is, 1.x Newton devices without the December 1995 system update (xxx333).
- * The Newton will spit strings representing the names. In this case,
- * you might want to 'flatten' the frames yourself using the CDILs but not FDILS.
- * "NONE" -- that soup is not available.
- */
- length = 4;
- CHECKDILERROR((short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0));
- response[4] = 0;
- if (strcmp(response, "DRNK") == 0)
- gInputMode = kDrinkMode;
- else if (strcmp(response, "SPIT") == 0)
- gInputMode = kSpitMode;
- else if (strcmp(response, "NONE") == 0) {
- PostAlertMessage("Could not open that soup on Newton.", "", "", "");
- CDPipeDisconnect(ourPipe);
- return(0);
- }
-
- length = 4;
-
- /* receive a response; "END " for no more entries, "ENTR" for another soup entry */
- CHECKDILERROR((short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0));
-
- response[4] = 0; /* make it a c string */
- if (strcmp(response, "END ") == 0) { /* if there are no more entries */
- CDPipeDisconnect(ourPipe);
- PostAlertMessage("At end...", "", "", "");
- return(0);
- }
- if (strcmp(response, "ENTR") != 0) {
- PostAlertMessage("Received unknown command:", response, "", "");
- CDPipeDisconnect(ourPipe);
- return(0);
- }
-
- /* read frame as unbound data */
- gThisObject = FDCreateObject(kDILFrame, nil);
-
- gReceivedStringLen = kMAXSTR;
- longLen = 4;
- if (gInputMode == kDrinkMode) {
- fErr = (short) FDget(gThisObject, kDILFrame, ourPipe, Timeout, (CDILPipeCompletionProcPtr)SoupDrinkCallback, 0);
- } else {
- // we're in "spit" mode; the newton says it can't send frames.
- fErr = (short) CDPipeRead(ourPipe, (void *) &gReceivedStringLen, &longLen, &eom,Swapping,Encoding,Timeout,0,0);
- if (fErr == 0)
- fErr = (short) CDPipeRead(ourPipe, (void *) &gReceivedString[0], &gReceivedStringLen, &eom,
- Swapping,Encoding,Timeout,(CDILPipeCompletionProcPtr)SoupDrinkCallback, 0);
- }
-
- if (fErr) {
- CDPipeDisconnect(ourPipe);
- PostAlertMessage("Read returned",ErrorStrings(fErr, gTempBuffer) ,"", "");
- return 0;
- }
-
- return fErr;
- }
-
-
- /********************************************************************************
- * SoupDrinkCallback
- *
- * SoupDrinkCallback is the drinking soup 'read' callback function
- */
- /* for 16 bit Windows... void FAR _loadds */
- #ifdef forWin16
- void FAR _loadds SoupDrinkCallback (CommErr errorValue, void *pData, Size Count, long refCon, long lFlags)
- #else
- static void SoupDrinkCallback (CommErr errorValue, void *pData, Size Count, long refCon, long lFlags)
- #endif
- {
- FILE *fp; /* file reference */
- slotDefinition *list = nil;
- long fErr = 0, len = 3;
- long longLen;
- long length;
- char response[255];
- Boolean eom;
- short x;
-
- if (errorValue)
- {
- Str255 refConStr;
-
- sprintf((char*) refConStr, "%d", Count);
- PostAlertMessage("Read returns:", (char*) refConStr, ". Error: ",
- ErrorStrings(errorValue, gTempBuffer));
- return;
- }
-
- /* open file for entry (append) */
- fp = fopen("SoupData.out", "w+");
- if (!fp)
- {
- PostAlertMessage("Could not open file", "", "", "");
- return;
- }
-
- do { /* traverse frames */
- if (gInputMode == kSpitMode) /* we are just receiving strings, not frames */
- {
- gReceivedString[gReceivedStringLen] = 0; /* turn it into c string */
- fprintf(fp, gReceivedString); /* send the string to the file */
- fprintf(fp, "\n"); /* send a carriage return char */
- }
- else
- {
-
- /* We should have an unbound frame list */
- list = FDGetUnboundList(gThisObject);
- if (!list) /* if not, we got an empty soup frame?; fail! */
- break;
-
- /* traverse list */
- for (x= 0; x < list->peerCnt; x++)
- printTree(fp, &list[x], 1);
-
- fputc('\n', fp);
- fputc('\n', fp);
- fputc('\n', fp);
-
- FDFreeUnboundList(gThisObject, list);
- list = nil;
- }
-
- if (fErr)
- PostAlertMessage("Unboundlist stuff returns:", ErrorStrings(fErr, gTempBuffer), "", "");
- else
- {
- /* read next frame */
-
- len = 3;
- fErr = CDPipeWrite(ourPipe, (void *)"OK\4", &len, true,Swapping,Encoding,Timeout,0,0) ; /* acknowledge receipt! */
- if (!fErr)
- {
- length = 4;
-
- /* receive a response; "END " for no more entries, "ENTR" for another soup entry */
- fErr = (short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0);
- if (fErr)
- {
- PostAlertMessage("Read returns:",ErrorStrings(fErr, gTempBuffer) ,"", "");
- return;
- }
-
- response[4] = 0; /* make it a c string */
- if (strcmp(response, "END ") == 0) { /* if there are no more entries */
- CDPipeDisconnect(ourPipe);
- break;
- }
- if (strcmp(response, "ENTR") != 0) {
- PostAlertMessage("Received unknown command: ", response, "", "");
- break;
- }
- gReceivedStringLen = kMAXSTR;
- longLen = 4;
-
- if (gInputMode == kDrinkMode)
- fErr = FDget(gThisObject, kDILFrame, ourPipe, 500*60, 0, 0);
- else {
- fErr = (short) CDPipeRead(ourPipe, (void *) &gReceivedStringLen, &longLen, &eom,Swapping,Encoding,Timeout,0,0);
- fErr = (short) CDPipeRead(ourPipe, (void *) &gReceivedString[0], &gReceivedStringLen, &eom,Swapping,Encoding,Timeout,0,0);
- }
- }
- }
- } while (!fErr && gThisObject);
-
-
- /* Clean up */
- if (fErr)
- PostAlertMessage("At end of soupdrink: ", ErrorStrings(fErr, gTempBuffer), "", "");
-
- fflush(fp);
- if (list)
- FDFreeUnboundList(gThisObject, list);
- fclose(fp);
- FDDisposeObject(gThisObject);
- CDPipeDisconnect(ourPipe);
- }
-
-
-
-
- /*
- * UploadNewName
- *
- * This function connects to a Newton and sends it a "name" for the names application.
- */
- CommErr UploadNewName ()
- {
- CommErr fErr = 0;
- void *entry, *name;
- void *phones;
- long cardType = 4, len;
- char pClass[] = "person";
- char fName[] = "Howard";
- char lName[] = "Duck";
- char phoneNo[] = "555-1212";
- char addr[] = "123 Sesame Street";
- char town[] = "Anytown";
- char state[] = "CA";
- char zip[] = "95014";
- char sName[] = "Duck";
- char response[5];
- long length;
- Boolean eom;
- long endTime;
-
-
- fErr = (short) InitializePipe();
- if (fErr)
- return fErr; // don't need to dispose pipe if error
-
- // make the connection!
- CHECKDILERROR((short) CDPipeListen(ourPipe, kDefaultTimeout, 0, 0 ) );
- #ifndef _windows
- CHECKDILERROR((short) CDPipeAccept(ourPipe));
- #else
- // This code doesn't need to be done on the MacOS side, but is currently required
- // for Windows. You need to loop a little bit for the connection state to be
- // set to kCDIL_ConnectPending. It might not do that if there's nobody on the
- // other side of the cable, though!
-
- // Loop until the Newton device connects
- endTime = CurrentTimeInSeconds() + kTimeoutInSecs; // time at which we should stop looping
- while (CurrentTimeInSeconds() < endTime) {
- if (CDGetPipeState(ourPipe) == kCDIL_ConnectPending) {
- CHECKDILERROR((short) CDPipeAccept(ourPipe));
- break;
- } else
- CDIdle(ourPipe);
- }
-
- if (CurrentTimeInSeconds() >= endTime) { // did we time out?
- CDPipeDisconnect(ourPipe) ;
- return kOurTimeoutError;
- }
- #endif
-
- /* Create an object */
-
- // in the future, errors should delete name, phones, entry objects.
-
- name = FDCreateObject(kDILFrame, NULL);
- CHECKDILERROR((short) FDbindSlot(name, "Class", (void *)&pClass, kDILSymbol, strlen(pClass), -1, NULL));
- CHECKDILERROR((short) FDbindSlot(name, "first", (void *)&fName, kDILString, strlen(fName), -1, NULL));
- CHECKDILERROR((short) FDbindSlot(name, "last", (void *)&lName, kDILString, strlen(lName), -1, NULL));
-
- phones = FDCreateObject(kDILArray, NULL);
- CHECKDILERROR((short) FDbindSlot(phones, "HomePhone", (void *)&phoneNo, kDILString, strlen(phoneNo), -1, NULL));
-
- entry = FDCreateObject(kDILFrame, NULL);
- CHECKDILERROR((short) FDbindSlot(entry, "cardType", (void *)&cardType, kDILInteger, sizeof(int), -1, NULL)) ;
- CHECKDILERROR((short) FDbindSlot(entry, "Name", (void *)name, kDILFrame, 0, -1, NULL));
- CHECKDILERROR((short) FDbindSlot(entry, "Address", (void *)&addr, kDILString, strlen(addr), -1, NULL)) ;
- CHECKDILERROR((short) FDbindSlot(entry, "City", (void *)&town, kDILString, strlen(town), -1, NULL)) ;
- CHECKDILERROR((short) FDbindSlot(entry, "Region", (void *)&state, kDILString, strlen(state), -1, NULL)) ;
- CHECKDILERROR((short) FDbindSlot(entry, "Postal_Code", (void *)&zip, kDILString, strlen(zip), -1, NULL)) ;
- CHECKDILERROR((short) FDbindSlot(entry, "phones", (void *)phones, kDILArray, 0, -1, NULL)) ;
- CHECKDILERROR((short) FDbindSlot(entry, "sorton", (void *)&sName, kDILString, strlen(sName), 0, "Name")) ;
-
- /* Initiate conversation */
- len = 5;
- CHECKDILERROR((short) CDPipeWrite (ourPipe, (void *)"NAME\4", &len, true, Swapping,Encoding,Timeout, 0, 0)) ;
-
- /* Send a frame */
- CHECKDILERROR((short) FDput(entry, kDILFrame, ourPipe)) ;
-
- FDDisposeObject(phones);
- FDDisposeObject(name);
- FDDisposeObject(entry);
-
- // wait for the ack back from the Newton (or for 30 seconds) before we disconnect
- length = 2;
- CHECKDILERROR((short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0));
-
- CDPipeDisconnect(ourPipe) ;
-
- return fErr;
-
- }
-
-
-
-
- void printEntry (FILE * fp, slotDefinition *thisEntry)
- {
- if (thisEntry->slotName)
- fprintf( fp, "%s : ", thisEntry->slotName);
-
- switch (thisEntry->varType)
- {
- case kDILCharacter: /* ASCII Character */
- fprintf( fp, "'%c'\n", *(char *)thisEntry->var);
- break;
-
- case kDILUnicodeCharacter: /* Unicode Character */
- {
- char c = *(((char *)thisEntry->var)+1);
- fprintf( fp, "$%c\n", (char *)c);
- }
- break;
-
- case kDILString: /* String (null-terminated) */
- if (thisEntry->oClass)
- // there's a special class defined for this string; show it.
- fprintf( fp, "\"%s\" (class '%s)\n", (char *)thisEntry->var, (char *)thisEntry->oClass);
- else
- // generic string; no special class.
- fprintf( fp, "\"%s\"\n", (char *)thisEntry->var);
- break;
-
- case kDILBoolean: /* Boolean */
- if (*(Boolean *)thisEntry->var)
- fprintf( fp, "TRUE\n");
- else
- fprintf( fp, "FALSE\n");
- break;
-
- case kDILImmediate: /* Indeterminate Immediate type */
- case kDILInteger: /* Integer (4 byte) */
- fprintf( fp, "#%ld\n", *(long *)thisEntry->var);
- break;
-
- case kDILPlainArray: /* Anonymous Array */
- fprintf (fp, "PLAINARRAY\n");
- break;
-
- case kDILArray: /* Named Array */
- if (thisEntry->oClass)
- fprintf (fp, "NAMEDARRAY (class '%s)\n", thisEntry->oClass);
- else
- fprintf (fp, "NAMEDARRAY (No class???)\n");
- break;
-
- case kDILFrame: /* Frame */
- fprintf (fp, "FRAME \n");
- break;
-
- case kDILSmallRect: /* Small rect */
- fprintf (fp, "SMALLRECT\n");
- break;
-
- case kDILPrecedent: /* Repeated Item */
- fprintf (fp, "PRECEDENT %s\n", (char *)thisEntry->var);
- break;
-
- case kDILSymbol: /* Object Symbol */
- fprintf( fp, "'%s\n", (char *)thisEntry->var);
- break;
-
- case kDILBinaryObject: /* Small Binary Object ( < 32K ) */
- if (thisEntry->oClass)
- if (0==strcmp(thisEntry->oClass,"Real")) {
- double tmpDouble;
- #ifdef _windows
- // ieee reals have bytes in the opposite order...
- unsigned long tmpWord1;
- unsigned long tmpWord2;
- tmpWord1 = ((unsigned long *)thisEntry->var)[0];
- tmpWord2 = ((unsigned long *)thisEntry->var)[1];
- tmpWord1 = ((tmpWord1 & 0x000000ff) << 24) |
- ((tmpWord1 & 0x0000ff00) << 8) |
- ((tmpWord1 & 0x00ff0000) >> 8) |
- ((tmpWord1 & 0xff000000) >> 24);
- tmpWord2 = ((tmpWord2 & 0x000000ff) << 24) |
- ((tmpWord2 & 0x0000ff00) << 8) |
- ((tmpWord2 & 0x00ff0000) >> 8) |
- ((tmpWord2 & 0xff000000) >> 24);
- ((unsigned long *)&tmpDouble)[0] = tmpWord2;
- ((unsigned long *)&tmpDouble)[1] = tmpWord1;
- #else
- tmpDouble = *(double *)thisEntry->var;
- #endif
- fprintf( fp, "%f\n", tmpDouble);
- }
- else
- fprintf( fp, "<%s, length %ld>\n", thisEntry->oClass, (ulong *) thisEntry->length);
- else
- fprintf( fp, "<binary, length %ld>\n", (ulong *) thisEntry->length);
- break;
-
- case kDILNIL: /* nil object */
- fprintf (fp, "NIL\n");
- break;
-
- case kDILBLOB: /* Large Binary Object */
- fprintf (fp, "BLOB\n");
- break;
-
- default: // ~~~~~ ignore these
- fprintf (fp, "UNKNOWN TYPE\n");
- break;
- }
- }
-
- //========================================================================================
- // printTree
-
- // printTree pretty prints the output, traversing the simple "tree" of data
- //========================================================================================
- void printTree (FILE * fp, slotDefinition *thisEntry, short depth)
- {
- short i;
- short y;
-
- for (i = 0; i < depth; i++)
- fputc('\t', fp);
-
- printEntry(fp, thisEntry);
-
- if (thisEntry->children)
- for (y= 0; y < thisEntry->childCnt; y++)
- printTree(fp, &(thisEntry->children[y]), depth + 1);
- }
-
-
- /* ErrorStrings
- *
- * Purpose: return error string based on error number from the CDIL or FDIL
- */
- char* ErrorStrings(CommErr theErr, char* theString)
- {
- switch (theErr)
- {
- case kOurTimeoutError: strcpy((char*) theString,
- (char*) "Timeout error. (Determined by SoupDrink)"); break;
- case -97: strcpy((char*) theString,
- (char*) "The port is busy. Quit the relevant application or restart if necessary (from ATalk Driver)"); break;
-
- // CDIL errors (see DILCPipe.h)
- case -28701: strcpy((char*) theString,
- (char*) "Error on memory allocation."); break;
- case -28702: strcpy((char*) theString,
- (char*) "DIL pipe was set to a bad state."); break;
- case -28703: strcpy((char*) theString,
- (char*) "An unknown exception has occurred."); break;
- case -28704: strcpy((char*) theString,
- (char*) "The queue of asynchronous calls is full."); break;
- case -28705: strcpy((char*) theString,
- (char*) "Pipe has not been initialized."); break;
- case -28706: strcpy((char*) theString,
- (char*) "Parameter passed in was invalid."); break;
- case -28707: strcpy((char*) theString,
- (char*) "Pipe is not ready for operation."); break;
- case -28708: strcpy((char*) theString,
- (char*) "Timeout during DIL operation."); break;
-
- // FDIL errors (see HLFDIL.h)
- case -28801: strcpy((char*) theString,
- (char*) "Out of heap memory"); break;
- case -28802: strcpy((char*) theString,
- (char*) "Out of temporary or other memory"); break;
- case -28803: strcpy((char*) theString,
- (char*) "Unknown slot"); break;
- case -28804: strcpy((char*) theString,
- (char*) "Slot size exceeded"); break;
- case -28805: strcpy((char*) theString,
- (char*) "Slot size is required"); break;
- case -28806: strcpy((char*) theString,
- (char*) "Unexpected data type"); break;
-
- // other errors
- case -28003: strcpy((char*) theString,
- (char*) "The communication operation was aborted."); break;
- case -28009: strcpy((char*) theString,
- (char*) "Bad connection detected"); break;
- case -28017: strcpy((char*) theString,
- (char*) "Out of memory"); break;
- case -28029: strcpy((char*) theString,
- (char*) "Cannot connect to modem; no response."); break;
- case -28030: strcpy((char*) theString,
- (char*) "Disconnection detected."); break;
- case -28100: strcpy((char*) theString,
- (char*) "Disconnect occurred while reading."); break;
- case -28101: strcpy((char*) theString,
- (char*) "An error occurred while reading."); break;
- case -28102: strcpy((char*) theString,
- (char*) "The communication tool was not found"); break;
- case -28103: strcpy((char*) theString,
- (char*) "Bad modem tool version"); break;
- default: sprintf(theString, "%ld", theErr);
- }
- return (char*) theString;
- }
-
-